<?php

class LiveraidController extends Zend_Controller_Action
{    
    
    public function indexAction()
    {
        $raid = Raids::getById($this->_request->getParam('raid'));
        
        // Display a error if we dont have a valid raid
        if (!$raid) {
            echo "Invalid raid"; //TODO: Display a colorful message here
            return;
        }
        
        // Assign the raid to the view
        $this->view->raid = $raid;
        
        // Get all dungeons (this list is fairly static so no need to fetch after the view is init)
        $dungeons = new Dungeons();
        $this->view->dungeons = $dungeons->fetchAll();
    }
    
    /**
     * Ajax action.
     * 
     * Will return all the chacters in the raid at a given time.
     * Can also limit the result to characters whos name is matched by a string.
     * Can also return characters not in the raid.
     * 
     * Parameters:
     *      raid: this should be the raid id, 
     *      time: the raid event time
     *      q: a query string, only characters whos name starts with q will be returned (case-insensitive)
     *      inverted: find characters not in raid instead
     * 
     * TODO: raid should be renamed to raidId for consistency
     */
    public function getCharactersInRaidAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        if (!$this->_request->isPost()){
            echo $this->_helper->jsonError("Request is not Post!");
            return;
        }
        
        $raid = Raids::getById($this->_request->getParam('raid'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid Raid");
            return;
        }
        
        // Get the name query if one is set
        $query = $this->_request->getParam('q');
        $query = is_string($query) ? strtolower($query) : null;
        
        // Get the time parameter if one is set
        $time = $this->_request->getParam('time');
        $time = is_numeric($time) ? $time : null;
        
        // Should the result be inverted so we get the characters not in the raid
        $inverted = $this->_request->getParam('inverted', null);
        
        if (!empty($inverted)) {
            $characters = $raid->getCharactersNotInRaid($time);
        } else {
            $characters = $raid->getCharactersInRaid($time);
        }
        
        $result = array();        

        foreach ($characters as $character) {
            
            // Include the character if no query is given or the string begins with the query
            $include = !$query || ($query && strncmp(strtolower($character->name), $query, strlen($query)) == 0);
            
            if ($include) {
                $result[] =  array(
                    'name' => $character->name, 
                    'id'   => $character->id,
                    'info' => $character->findParentRow('Classes', 'Classes')->name
                );
            }
        }

        sort($result);
        
        echo $this->_helper->jsonResponse($result);
    }
    
    /*
     * Ajax action.
     * 
     * The horible behemoth action that returns all events for the raid.
     * 
     * TODO: consider splitting this into smaller utility functions. 
     * Especially the dkp_adjustment code has alot of redundency.
     * 
     */
    public function getRaidEventsAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        if (!$this->_request->isPost()){
            echo $this->_helper->jsonError("Request is not Post!");
            return;
        }
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid Raid");
            return;
        }
        
        // The results array will carry the final response
        $result = array();
        
        // We sometimes need to have the highest event time 
        $highestTime = $raid->getHighestTime();
        
        $raidRosterChanges = $raid->findDependentRowset('RaidRosterChanges','Raids');
        foreach ($raidRosterChanges as $change) {
            
            // There are only two types of roster changes (join and leave)
            $type = 'join';
            if ($change->is_leave) {
                $type = 'leave';
            }
            
            $dkpAdjustment = null;
            if ($change->dkp_adjustment_id){
                
                // Find the adjustment and the associated character (note: there is only one character for a roster change adjustment)
                $dkpAdjustmentRow = $change->findParentRow('DkpAdjustments','DkpAdjustments');
                //$dkpAdjustmentsCharacters = $dkpAdjustmentRow->findDependentRowset('DkpAdjustmentsCharacters','DkpAdjustments');
                //$dkpAdjustmentsCharacter = $dkpAdjustmentsCharacters->current()->findParentRow('Characters','Characters');
                //$dkpAdjustmentClass = $dkpAdjustmentsCharacter->findParentRow("Classes");
                
                $dkpAdjustment = array(    
                    'id'                => $dkpAdjustmentRow->id,
                    'dkp_event_id'      => $dkpAdjustmentRow->dkp_event_id,
                    'dkp_event_name'    => $dkpAdjustmentRow->findParentRow('DkpEvents','DkpEvents')->name,
                    'dkp_earned'        => $dkpAdjustmentRow->dkp_earned,
                    'dkp_spent'         => $dkpAdjustmentRow->dkp_spent,
                    /*'character_id'      => $dkpAdjustmentsCharacter->id,
                    'character_name'    => $dkpAdjustmentsCharacter->name,
                    'class_id'		    => $dkpAdjustmentsCharacter->class_id,
                    'class_name'        => $dkpAdjustmentClass->name,
                    'class_icon_small'  => $dkpAdjustmentClass->icon_small,
                    'class_icon_large'  => $dkpAdjustmentClass->icon_large,*/
                );
            }
            
            $character = $change->findParentRow('Characters','Characters');
            $class = $character->findParentRow("Classes");
            
            $result[] = array(
                'time'              => $change->time,
                'id'                => $change->id,
                'type'              => $type,
                'character_id'      => $change->character_id,
                'character_name'    => $character->name,
                'class_id'          => $class->id,
                'class_name'        => $class->name,
                'class_icon_small'  => $class->icon_small,
                'class_icon_large'  => $class->icon_large,
                'dkp_adjustment'    => $dkpAdjustment,
                'note'              => $change->note,
            );
            
            unset($dkpAdjustmentRow);
            unset($character);
            unset($class);
        }
        
        $raidKills = $raid->findDependentRowset('RaidKills','Raids');        
        foreach ($raidKills as $raidKill) {
            $boss = null;
            $dkpAdjustment = null;
            
            if($raidKill->boss_id){
                $boss = array(    
                    'id'        => $raidKill->boss_id,
                    'name'      => $raidKill->findParentRow('Bosses','Bosses')->name
                );
            }
            
            if ($raidKill->dkp_adjustment_id) {
                
                $dkpAdjustmentRow = $raidKill->findParentRow('DkpAdjustments','DkpAdjustments');
                
                $dkpAdjustmentsCharacterRowSet = $dkpAdjustmentRow->findDependentRowset('DkpAdjustmentsCharacters','DkpAdjustments');
                $dkpAdjustmentCharacters = array();
                
                foreach($dkpAdjustmentsCharacterRowSet as $entry){
                    $dkpAdjustmentCharacters[] = array(    
                        'character_id'      => $entry->findParentRow('Characters','Characters')->id,
                        'character_name'    => $entry->findParentRow('Characters','Characters')->name
                    );
                }
                
                $dkpAdjustment = array(    
                    'id'                => $dkpAdjustmentRow->id,
                    'dkp_event_id'      => $dkpAdjustmentRow->dkp_event_id,
                    'dkp_event_name'    => $dkpAdjustmentRow->findParentRow('DkpEvents','DkpEvents')->name,
                    'dkp_earned'        => $dkpAdjustmentRow->dkp_earned,
                    'dkp_spent'         => $dkpAdjustmentRow->dkp_spent,
                    'characters'        => $dkpAdjustmentCharacters,
                    'note'              => $dkpAdjustmentRow->note
                );
            }
            
            
            
            
            $raidDrops = $raidKill->findDependentRowset('RaidDrops','RaidKills');
            $resultDrops = array();
            foreach($raidDrops as $drop){
           		
            	$dropDkpAdjustment = null;	
            	
	   			if ($drop->dkp_adjustment_id) {
	                
	                $dkpAdjustmentRow = $drop->findParentRow('DkpAdjustments','DkpAdjustments');
	                
	                $dkpAdjustmentsCharacterRowSet = $dkpAdjustmentRow->findDependentRowset('DkpAdjustmentsCharacters','DkpAdjustments');
	                $dkpAdjustmentCharacters = array();
	                
	                foreach($dkpAdjustmentsCharacterRowSet as $entry){
	                    $dkpAdjustmentCharacters[] = array(    
	                        'character_id'     => $entry->findParentRow('Characters','Characters')->id,
	                        'character_name'   => $entry->findParentRow('Characters','Characters')->name
	                    );
	                }
	                
	                $dropDkpAdjustment = array(    
	                    'id'               => $dkpAdjustmentRow->id,
	                    'dkp_event_id'     => $dkpAdjustmentRow->dkp_event_id,
	                    'dkp_event_name'   => $dkpAdjustmentRow->findParentRow('DkpEvents','DkpEvents')->name,
	                    'dkp_earned'       => $dkpAdjustmentRow->dkp_earned,
	                    'dkp_spent'        => $dkpAdjustmentRow->dkp_spent,
	                    'characters'       => $dkpAdjustmentCharacters,
	                    'note'             => $dkpAdjustmentRow->note
	                );
	            }
            	
            	
            	$resultDrops[] = array(	
            		'id'				=> $drop->id,
            		'item_id'			=> $drop->item_id,
            	    'item_name'			=> $drop->findParentRow('Items','Items')->name,
            	    'item_quality'		=> $drop->findParentRow('Items','Items')->quality,
            		'character_id'		=> $drop->character_id,
            	    'character_name'	=> $drop->findParentRow('Characters','Characters')->name,
            		'dkp_adjustment'    => $dropDkpAdjustment,
            		'note'				=> $drop->note
            	);  	
            	
            }    
            
            $result[] = array(  
			    'time'              => $raidKill->time,
                'id'                => $raidKill->id,
                'type'              => 'kill',
                'boss'              => $boss,
                'dkp_adjustment'    => $dkpAdjustment,
                'drops'			    => $resultDrops,
                'note'              => $dkpAdjustment['note'],
            );
            
        }
        
        
        $dungeonChanges = $raid->findDependentRowset('RaidDungeonChanges','Raids');
        foreach ($dungeonChanges as $change){
            $result[] = array(    
                'time'          => $change->time,
                'id'            => $change->id,
                'type'          => "dungeon",
                'dungeon_id'    => $change->dungeon_id,
                'dungeon_name'  => $change->findParentRow('Dungeons','Dungeons')->name,
                'is_last_event' => ($change->time == $highestTime) ? true : false
            );
        }
        
        // Sort the events by time
        usort($result, "__eventSort");

        echo $this->_helper->jsonResponse($result);
    }
    

    public function addJoinAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid Raid");
            return;
        }
        
        $character = Characters::getById($this->_request->getParam('characterId'));
        if (!$character) {
            echo $this->_helper->jsonError("Invalid character!");
            return;
        }
        
        $time = $this->_request->getParam('time');
        
        $time = is_numeric($time) ? $time : null;

        $note = $this->_request->getParam('note');
        
        if ($raid->addJoin($character->id,$note,$time)) {
            echo $this->_helper->jsonResponse();
        } else {
            echo $this->_helper->jsonError("Could not add the character.");
        }
    }
    
    /*
     * TODO: We need to check if the user already has a character in the raid. Or what?
     */
    public function addLeaveAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        if (!$this->_request->isPost()){
            echo $this->_helper->jsonError("Request is not Post!");
            return;
        }
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid raid!");
            return;
        }
        
        $character = Characters::getById($this->_request->getParam('characterId'));
        if (!$character) {
            echo $this->_helper->jsonError("Invalid character!");
            return;
        }
        
        $spent = $this->_request->getParam('spent');
        if(!is_numeric($spent) && $spent != null){
            echo $this->_helper->jsonError("Invalid dkp spent value!");
            return;
        }
        
        $dkpEvent = DkpEvents::getById($this->_request->getParam('dkpEventId'));
        if (!$dkpEvent) {
            echo $this->_helper->jsonError("Invalid dkpEvent!");
            return;
        }
        
        $time = $this->_request->getParam('time');
        $time = is_numeric($time) ? $time : null;
        
        $note = $this->_request->getParam('note');
        
        if ($raid->addLeave($character->id,$spent,$dkpEvent->id,$note,$time)) {
            echo $this->_helper->jsonResponse();
        } else {
            echo $this->_helper->jsonError("Could not leave the character.");
        }
    }
    
    /*
     * AJAX action for adding a Kill
     */
    public function addKillAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid raid!");
            return;
        }
        
        $time = $this->_request->getParam('time');
        if ( (!is_numeric($time) && $time != null) || $time === 0){
            echo $this->_helper->jsonError("Invalid time!");
            return;
        }
        
        $boss = Bosses::getById($this->_request->getParam('bossId'));
        if (!$boss) {
            echo $this->_helper->jsonError("Invalid boss!");
            return;
        }
        
        // TODO: Virker ikke af en eller anden grund (empty virker fint)
        $dkpEventId = $this->_request->getParam('dkpEventId');
        if(    !is_numeric($dkpEventId) && $dkpEventId != null && $dkpEventId != DkpEvents::$FARM_KILL && 
            $dkpEventId != DkpEvents::$PROGRESS_KILL && $dkpEventId != DkpEvents::$FIRST_TIME_KILL        ){
                
            echo $this->_helper->jsonError("Invalid dkp event!");
            return;
        }
        
        $earned = $this->_request->getParam('earned');
        if(!is_numeric($earned) && $earned != null){
            echo $this->_helper->jsonError("Invalid dkp amount!");
            return;
        }
        
        $note = $this->_request->getParam('note');
        
        if ( $raid->addKill($time, $boss->id, $dkpEventId, $earned, $note) ) {
            echo $this->_helper->jsonResponse();
        } else {
            echo $this->_helper->jsonError("Error in RaidRow->addKill in LiveraidController->addKillAction, parameter: 
            	\n time:". $time . "\n bossID: " . $boss->id . "\n dkpEventId: " . $dkpEventId . "\n earned: " . $earned . "\n note: " . $note);
        }
        
    }
    
    /**
     * AJAX method for getting the items belonging to a boss
     * @return unknown_type
     */
    public function getBossItemsAction()
    {
    	
        $this->_helper->viewRenderer->setNoRender();
        
    	$boss = Bosses::getById($this->_request->getParam('bossId'));
    	if (!$boss){
    		echo $this->_helper->jsonError('Invalid bossId!');
            return;
    	}
    	
    	$items = array();
    	$itemsRowset = $boss->findManyToManyRowset('Items','BossesItems','Bosses','Items');
    	foreach($itemsRowset as $item) {
    	    $itemArray = $item->toArray();
    	    $itemArray['dkpPrice'] = $item->getDkpPrice();
    	    $items[] = $itemArray;
    	}
    	
    	echo $this->_helper->jsonResponse($items);	
    }
    
    
    /*
     * AJAX function to add a drop to a kill
     * input: $raidId, $killId,$characterId,$itemId,$dkpSpent,$note
     */
    public function addDropAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        $kill = RaidKills::getById($this->_request->getParam('killId'));
        if (!$kill) {
            echo $this->_helper->jsonError("Invalid raidKillId!");
            return;
        }
        
        $raidId = $this->_request->getParam('raidId');
        if ($raidId != $kill->raid_id){
            echo $this->_helper->jsonError("Invalid raidId!");
            return;
        }
        
        $character = Characters::getById($this->_request->getParam('characterId'));
        if (!$character) {
            echo $this->_helper->jsonError("Invalid character!");
            return;
        }
        
        $item = Items::getById($this->_request->getParam('itemId'));
        if (!$item) {
            echo $this->_helper->jsonError("Invalid itemId!");
            return;
        }
        
        $dkpSpent = $this->_request->getParam('dkpSpent');
        if (!is_numeric($dkpSpent) && $dkpSpent != null){
            echo $this->_helper->jsonError("Invalid dkpSpent!");
            return;
        }
        
        $note = $this->_request->getParam('note');
        
        if ($kill->addDrop($character->id,$item->id,$dkpSpent,$note)){
            echo $this->_helper->jsonResponse();
        }else {
            echo $this->_helper->jsonError("Error in RaidKillRow->addDrop in LiveraidController->addDrop");    
        }        
    }
    
    /*
     * AJAX funtion to remove a raid drop
     * input dropId raidId
     */
    public function removeDropAction()
    {   
        $this->_helper->viewRenderer->setNoRender();
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid raidId!");
            return;
        }
        
        $drop = RaidDrops::getById($this->_request->getParam('dropId'));
        if (!$drop) {
            echo $this->_helper->jsonError("Invalid dropId!");
            return;
        }
        
        if ($raid->removeDrop($drop)) echo $this->_helper->jsonResponse();
        else echo $this->_helper->jsonError("Error in RaidRow->removeDrop in LiveraidController->removeDrop!");
    }
    
    /*
     * AJAX action for changing the current dungeon of a raid
     * input: $raidId $dungeonId, $time = null
     */
    public function addDungeonChangeAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid raid!");
            return;
        }

        $dungeon = Dungeons::getById($this->_request->getParam('dungeonId'));
        if (!$dungeon) {
            echo $this->_helper->jsonError("Invalid dungeon!");
            return;
        }
        
        if ($raid->addDungeonChange($dungeon->id)) {
            echo $this->_helper->jsonResponse();
        } else {
            echo $this->_helper->jsonError("The raid is already in that dungeon.");
        }
    }
    
    /*
     * AJAX action for removing a raid dungeon change
     * input: $raidId $changeId
     */
    public function removeDungeonChangeAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid raid!");
            return;
        }
        
        $dungeonChangeId = $this->_request->getParam('dungeonChangeId');
        if(!is_numeric($dungeonChangeId)){
            echo $this->_helper->jsonError("Invalid dungeonChangeId!");
            return;
        }
        
        if ($raid->removeDungeonChange($dungeonChangeId)) {
            echo $this->_helper->jsonResponse();
        }
        else {
            echo $this->_helper->jsonError("Its only possible to remove a dungeon change if its the last event.");
        }
        
    }
    
    /*
     * AJAX action for removing a RosterChange 'join'
     * 
     */
    public function removeLeaveAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        if (!$this->_request->isPost()){
            echo "Request is not Post!";
            return;
        }
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo "Invalid Raid";
            return;
        }
        
        $rosterChangeId = $this->_request->getParam('rosterChangeId');
        if(is_numeric($rosterChangeId)){
            $raid->removeLeave($rosterChangeId);
            echo $this->_helper->jsonResponse();
        } else echo $this->_helper->jsonError("rosterChangeId is not numeric in removeLeaveAction()");
        
    }
    
    /*
     * AJAX action for removing a RosterChange 'join'
     */
    public function removeJoinAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        if (!$this->_request->isPost()){
            echo "Request is not Post!";
            return;
        }
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo "Invalid Raid";
            return;
        }
        
        $rosterChangeId = $this->_request->getParam('rosterChangeId');
        if(is_numeric($rosterChangeId)){
            $raid->removeJoin($rosterChangeId);
            echo $this->_helper->jsonResponse();
        } else {
            echo $this->_helper->jsonError("rosterChangeId is not numeric in removeJoinAction()");
        }
        
    }
    
    /*
     * AJAX function for removing a RaidKill
     */
    public function removeKillAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        if (!$this->_request->isPost()){
            echo "Request is not Post!";
            return;
        }
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo "Invalid Raid";
            return;
        }
        
        $raidKillId = $this->_request->getParam('raidKillId');
        if(is_numeric($raidKillId)){
            $raid->removeKill($raidKillId);
            echo $this->_helper->jsonResponse();
        } else {
            echo $this->_helper->jsonError("rosterChangeId is not numeric in removeJoinAction()");
        }
    }
    
    /*
     * AJAX function to return all the bosses that are associated with the
     * raid but has not yet been killed.
     */
    public function getAliveBossesAction()
    {
        $this->_helper->viewRenderer->setNoRender();
        
        $raid = Raids::getById($this->_request->getParam('raidId'));
        if (!$raid) {
            echo $this->_helper->jsonError("Invalid Raid");
            return;
        }
        
        $time = $this->_request->getParam('time');
        if ( (!is_numeric($time) && $time != null) || $time === 0){
            echo $this->_helper->jsonError("Invalid time!");
            return;
        }
        
        $aliveBosses = $raid->getAliveBossesToTime($time);
        $result = array();
        
        foreach ($aliveBosses as $id => $name){
            $result[] = array('id' => $id,'name' => $name);
        }
        
        echo $this->_helper->jsonResponse($result);
    }
}

function __eventSort($a, $b)
{
    if (!isset($a['time']) || !isset($b['time'])) {
        throw new Exception("missing time on event in __eventSort");
    }
    
    return $a['time'] - $b['time'];
}
